﻿// Copyright (c) 2012 - 2020 Jared Zheng <jaredz at outlook dot com>
// Buddha Framework is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//          http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
//
// Create : 2012-12-01 version 0.1 Jared Zheng <jaredz at outlook dot com>
// Update : 2018-12-05 version 3.1.5 Jared Zheng <jaredz at outlook dot com>

#ifndef __GATE_SESSION_H__
#define __GATE_SESSION_H__

#pragma once

#include "refcount.h"
#include "sessionbase.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 业务会话数据
struct tagGATE_SESSION : public SESSION_ID
{
public:
    UInt    uStatus;   // atomics
    UInt    uRet;      //
};
typedef tagGATE_SESSION GATE_SESSION, *PGATE_SESSION;

///////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 业务会话
class CGateSession : public CTRefCount<CGateSession>
{
public:
    typedef CTArray<ULLong>               ARY_ROUTINEID;
    typedef CTMap<ULLong, ULLong>         ROUTINEID_MAP, *PROUTINEID_MAP;
    typedef CTMap<ULLong, ULLong>::PAIR   ROUTINEID_MAP_PAIR;
public:
    CGateSession(void)
    {
    }

    virtual ~CGateSession(void)
    {
    }
public:
    void Reset(void)
    {
        MM_SAFE::Set(&m_Session, 0, sizeof(GATE_SESSION));
    }

    LLong GetUpdate(void)
    {
        return m_Session.llUpdate;
    }

    void SetUpdate(LLong llUpdate)
    {
        CAtomics::Exchange64<LLong>(&m_Session.llUpdate, llUpdate);
    }

    bool TrySetUpdate(LLong llCurUpdate, LLong llSetUpdate)
    {
        return (CAtomics::CompareExchange64<LLong>(&m_Session.llUpdate, llSetUpdate, llCurUpdate) == llCurUpdate);
    }

    bool CheckUpdate(LLong llUpdate)
    {
        return (CAtomics::CompareExchange64<LLong>(&m_Session.llUpdate, 0, 0) == llUpdate);
    }

    bool TimeoutUpdate(LLong llInterval)
    {
        return (CPlatform::GetRunningTime() > (m_Session.llUpdate + llInterval));
    }

    UInt GetVer(void)
    {
        return m_Session.uVer;
    }

    void SetVer(UInt uVer)
    {
        m_Session.uVer = uVer;
    }

    UInt GetTarget(void)
    {
        return m_Session.uTarget;
    }

    void SetTarget(UInt uTarget)
    {
        m_Session.uTarget = uTarget;
    }

    UInt GetType(void)
    {
        return m_Session.uType;
    }

    void SetType(UInt uType)
    {
        m_Session.uType = uType;
    }

    UInt GetId(void)
    {
        return m_Session.uId;
    }

    void SetId(UInt uId)
    {
        m_Session.uId = uId;
    }

    ULLong GetIId(void)
    {
        return m_Session.ullId;
    }

    void SetIId(ULLong ullId)
    {
        m_Session.ullId = ullId;
    }
    //--------------------------------------------
    UInt GetStatus(void)
    {
        return CAtomics::CompareExchange<UInt>(&m_Session.uStatus, 0, 0);
    }

    bool CheckStatus(UInt uStatus)
    {
        return (CAtomics::CompareExchange<UInt>(&m_Session.uStatus, 0, 0) == uStatus);
    }

    void SetStatus(UInt uStatus)
    {
        CAtomics::Exchange<UInt>(&m_Session.uStatus, uStatus);
    }

    bool TrySetStatus(UInt uCurStatus, UInt uSetStatus)
    {
        return (CAtomics::CompareExchange<UInt>(&m_Session.uStatus, uSetStatus, uCurStatus) == uCurStatus);
    }

    UInt GetRet(void)
    {
        return CAtomics::CompareExchange<UInt>(&m_Session.uRet, 0, 0);
    }

    void SetRet(UInt uRet)
    {
        CAtomics::Exchange<UInt>(&m_Session.uRet, uRet);
    }

    bool TrySetRet(UInt uCurRet, UInt uSetRet)
    {
        return (CAtomics::CompareExchange<UInt>(&m_Session.uRet, uSetRet, uCurRet) == uCurRet);
    }

    PByte GetSession(void)
    {
        return (PByte)&m_Session;
    }

    CNetAddr& GetAddr(void)
    {
        return m_Addr;
    }

    void SetAddr(CNetAddr& Addr)
    {
        m_Addr = Addr;
    }

    CBufReadStream& GetData(void)
    {
        return m_Data;
    }

    bool Link(ULLong ullRoutineId)
    {
        CSyncLockWaitScope scope(m_RoutineIdLock);
        if (m_RoutineId.Find(ullRoutineId) == nullptr)
        {
            m_RoutineId.Add(ullRoutineId);
        }
        return true;
    }

    bool LinkAck(ULLong ullRoutineId)
    {
        CSyncLockWaitScope scope(m_RoutineIdLock);
        ROUTINEID_MAP_PAIR* pPair = m_RoutineId.Find(ullRoutineId);
        if (pPair != nullptr)
        {
            pPair->m_V = STATUSL_LINKED;
        }
        return true;
    }

    bool Unlink(ULLong ullRoutineId = 0)
    {
        CSyncLockWaitScope scope(m_RoutineIdLock);
        if (ullRoutineId != 0)
        {
            ROUTINEID_MAP_PAIR* pPair = m_RoutineId.Find(ullRoutineId);
            if (pPair != nullptr)
            {
                pPair->m_V = STATUSL_RESERVED;
            }
        }
        else
        {
            // 和业务管理断开, 通知外网端REQ_MASTER
            // 重连完成以后, 通知外网端重连所有业务功能
            m_RoutineId.RemoveAll();
        }
        return true;
    }

    bool Logout(ARY_ROUTINEID& aRID)
    {
        CSyncLockWaitScope scope(m_RoutineIdLock);
        if (m_RoutineId.GetSize() > 0)
        {
            Int nCount = 0;
            for (PINDEX index = m_RoutineId.GetFirstIndex(); index != nullptr; )
            {
                ROUTINEID_MAP_PAIR* pPair = m_RoutineId.GetNext(index);
                if (pPair->m_V <= STATUSL_LINKED)
                {
                    aRID.Add(pPair->m_K);
                    ++nCount;
                }
            }
            m_RoutineId.RemoveAll();
            return (nCount > 0);
        }
        return false;
    }
public:
    GATE_SESSION         m_Session;
    CNetAddr             m_Addr;
    CBufReadStream       m_Data;
    // 会话连接的业务功能
    ROUTINEID_MAP        m_RoutineId;
    CSyncLock            m_RoutineIdLock;
};
typedef CTRefCountPtr<CGateSession>   CGateSessionPtr;

typedef CTMap<Socket_t, CGateSessionPtr>         GATE_SESSION_MAP, *PGATE_SESSION_MAP;
typedef CTMap<Socket_t, CGateSessionPtr>::PAIR   GATE_SESSION_MAP_PAIR;

#endif // __GATE_SESSION_H__
